﻿/*
Squared.Tiled
Copyright (C) 2009 Kevin Gadd

  This software is provided 'as-is', without any express or implied
  warranty.  In no event will the authors be held liable for any damages
  arising from the use of this software.

  Permission is granted to anyone to use this software for any purpose,
  including commercial applications, and to alter it and redistribute it
  freely, subject to the following restrictions:

  1. The origin of this software must not be misrepresented; you must not
     claim that you wrote the original software. If you use this software
     in a product, an acknowledgment in the product documentation would be
     appreciated but is not required.
  2. Altered source versions must be plainly marked as such, and must not be
     misrepresented as being the original software.
  3. This notice may not be removed or altered from any source distribution.

  Kevin Gadd kevin.gadd@gmail.com http://luminance.org/
*/

using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

namespace TowerDefence
{
    public interface IMap
    {        
        void Draw(SpriteBatch _batch, Rectangle _rectangle, Vector2 _viewportPosition);
        
        /// <summary>
        /// Number of tiles wide
        /// </summary>
        int Width { get; }

        /// <summary>
        /// Number of tiles high
        /// </summary>
        int Height { get; }

        /// <summary>
        /// Individual tile width
        /// </summary>
        int TileWidth { get; }

        /// <summary>
        /// Individual tile height
        /// </summary>
        int TileHeight { get; }
    }

    public class Map : IMap
    {
        public List<Tileset> Tilesets = new List<Tileset>();
        public List<Layer> Layers = new List<Layer>();
        private int width, height;
        private int tileWidth, tileHeight;

        public int Width 
        { 
            get { return this.width; } 
            set { this.width = value; } 
        }
        public int Height 
        { 
            get { return this.height; }
            set { this.height = value; } 
        }
        public int TileWidth 
        { 
            get { return this.tileWidth; }
            set { this.tileWidth = value; } 
        }
        public int TileHeight 
        { 
            get { return this.tileHeight; }
            set { this.tileHeight = value; } 
        }

        public static Map Load(string filename, ContentManager content)
        {
            var result = new Map();
            var settings = new XmlReaderSettings { ProhibitDtd = false };
            using (var stream = System.IO.File.OpenText(filename))
            using (var reader = XmlReader.Create(stream, settings))
                while (reader.Read())
                {
                    var name = reader.Name;

                    switch (reader.NodeType)
                    {
                        case XmlNodeType.DocumentType:
                            if (name != "map")
                                throw new Exception("Invalid map format");
                            break;
                        case XmlNodeType.Element:
                            switch (name)
                            {
                                case "map":
                                    {
                                        result.Width = int.Parse(reader.GetAttribute("width"));
                                        result.Height = int.Parse(reader.GetAttribute("height"));
                                        result.TileWidth = int.Parse(reader.GetAttribute("tilewidth"));
                                        result.TileHeight = int.Parse(reader.GetAttribute("tileheight"));
                                    } break;
                                case "tileset":
                                    {
                                        using (var st = reader.ReadSubtree())
                                        {
                                            st.Read();
                                            var tileset = Tileset.Load(st);
                                            result.Tilesets.Add(tileset);
                                        }
                                    } break;
                                case "layer":
                                    {
                                        using (var st = reader.ReadSubtree())
                                        {
                                            st.Read();
                                            var layer = Layer.Load(st);
                                            result.Layers.Add(layer);
                                        }
                                    } break;
                            }
                            break;
                        case XmlNodeType.EndElement:
                            break;
                        case XmlNodeType.Whitespace:
                            break;
                    }
                }

            foreach (var tileset in result.Tilesets)
            {
                // Strip the "../" from the start of the path - the level editor needs this, but XNA doesn't
                string imageDir = Path.GetDirectoryName(tileset.Image).Substring(3);
                tileset.Texture = content.Load<Texture2D>(
                    Path.Combine(imageDir, Path.GetFileNameWithoutExtension(tileset.Image))
                );
            }

            return result;
        }

        public void Draw(SpriteBatch batch, Rectangle rectangle, Vector2 viewportPosition)
        {
            foreach (var layer in Layers)
            {
                if (layer.Name != LayerNames.TERRAIN) continue;
                layer.Draw(batch, Tilesets, rectangle, viewportPosition, TileWidth, TileHeight);
            }
        }
    }
}
